// 1. 用于解决keep-alive需要name的问题，动态生成随机name供keep-alive使用
// 2. 用于解决transition动画内部结点只能为根元素的问题，单文件可写多结点
import type { DefineComponent, Component } from 'vue'
import { defineComponent, h, createVNode, ref, nextTick } from 'vue'
import reload from './reload.vue'
import NProgress from '@/utils/system/nprogress'
/**
 *
 * @param component 传入的组件
 * @returns 返回一个新的组件
 * @description 用于解决keep-alive需要name的问题，动态生成随机name供keep-alive使用
 * @description 用于解决transition动画内部结点只能为根元素的问题，单文件可写多结点
 * 这段代码是一个 TypeScript 函数定义，其名称为 `createNameComponent`。函数接受一个参数，该参数是一个返回异步操作的函数类型，并返回一个返回异步操作的函数类型。
 *具体来说，该函数期望传入一个函数类型参数 `component`，该函数返回一个 Promise 对象。最终，函数将返回一个函数类型，其返回值是一个 Promise 对象或 Vue 组件（使用 `DefineComponent` 类型），不带任何 props 和 emits。这意味着该函数旨在动态生成 Vue 组件。
 *从命名上看，该函数可能用于创建在运行时加载的异步组件。在调用该函数时，需要提供一个返回 Vue 组件对象的函数，即可实现异步组件的加载和注册。
 *要注意的是，该函数的实现并没有直接生成 Vue 组件，而是通过一个异步加载的过程来生成组件。也就是说，调用该函数会返回一个 Promise 对象，在 Promise 对象的 then 方法中可以获取到生成的 Vue 组件对象。
 */
export function createNameComponent(
  component: () => Promise<any>
): () => Promise<DefineComponent<{}, {}, any>> {
  return () => {
    //Promise对象里面的参数就是一个回调函数
    return new Promise((resolve) => {
      component().then((comm: DefineComponent<{}, {}, any>) => {
        const name = (comm.default.name || 'vueAdminBox') + '$' + Date.now()
        //使用 defineComponent 函数创建一个新的临时组件，用于包装真正的 Vue 组件、处理自定义逻辑和数据等等。
        const tempComm = defineComponent({
          name,
          setup() {
            const isReload = ref(false)
            let timeOut: any = null
            const handleReload = () => {
              isReload.value = true
              timeOut && clearTimeout(timeOut)
              NProgress.start()
              timeOut = setTimeout(() => {
                nextTick(() => {
                  NProgress.done()
                  isReload.value = false
                })
              }, 260)
            }
            return {
              isReload,
              handleReload,
            }
          },
          /**
           * 如果 isReload 为 true，则生成一个 div 元素，其子元素是一个与任何 Vue 组件都无关的 reload 图标。该图标会在组件被重新加载时显示。
           *如果 isReload 为 false，则运用 h() 工厂函数创建一个新的 VNode 并返回，使用 createVNode(comm.default) 来渲染原始的 Vue 组件。
           */
          render: function () {
            if (this.isReload) {
              return h('div', { class: 'el-main-box' }, [h(reload)])
            } else {
              return h('div', { class: 'el-main-box' }, [
                createVNode(comm.default),
              ])
            }
          },
        })
        resolve(tempComm)
      })
    })
  }
}
